#!/usr/bin/env python3
"""
S3 Bucket Create Tool - CreateBucket API 演示工具

这个工具演示如何使用 CreateBucket API 创建新的存储桶。

使用示例:
    python s3_bucket_create.py --name my-new-bucket
    python s3_bucket_create.py --name my-bucket --region us-west-2
    python s3_bucket_create.py --name-prefix myapp --count 3
    python s3_bucket_create.py --format json
    python s3_bucket_create.py --verbose
"""

import argparse
import boto3
import json
import sys
from datetime import datetime, timezone
from botocore.config import Config
from botocore.exceptions import ClientError, NoCredentialsError


class BucketCreateClient:
    """S3 桶创建客户端"""
    
    def __init__(self, endpoint_url='http://localhost:8000', 
                 access_key='AKIAIOSFODNN7EXAMPLE', 
                 secret_key='wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
                 region='us-east-1'):
        """
        初始化桶创建客户端
        
        Args:
            endpoint_url: S3 服务端点
            access_key: AWS Access Key
            secret_key: AWS Secret Key
            region: AWS 区域
        """
        self.endpoint_url = endpoint_url
        self.access_key = access_key
        self.secret_key = secret_key
        self.region = region
        self._client = None
    
    def _get_client(self):
        """获取 S3 客户端"""
        if self._client is None:
            self._client = boto3.client(
                's3',
                endpoint_url=self.endpoint_url,
                aws_access_key_id=self.access_key,
                aws_secret_access_key=self.secret_key,
                region_name=self.region,
                config=Config(s3={'addressing_style': 'path'})
            )
        return self._client


    def _validate_bucket_name(self, name):
        """验证桶名称是否符合规范"""
        import re
        
        # 基本长度检查
        if len(name) < 3 or len(name) > 63:
            return False, "桶名长度必须在 3-63 个字符之间"
        
        # 字符检查
        if not re.match(r'^[a-z0-9][a-z0-9.-]*[a-z0-9]$', name):
            return False, "桶名只能包含小写字母、数字、点号和连字符，且必须以字母或数字开头和结尾"
        
        # 连续点号检查
        if '..' in name:
            return False, "桶名不能包含连续的点号"
        
        # IP 地址格式检查
        if re.match(r'^\d+\.\d+\.\d+\.\d+$', name):
            return False, "桶名不能是 IP 地址格式"
        
        # 特殊前缀检查
        if name.startswith('xn--') or name.startswith('sthree-'):
            return False, "桶名不能以 'xn--' 或 'sthree-' 开头"
        
        return True, "桶名验证通过"


    def create_single_bucket(self, bucket_name, region=None):
        """简单格式创建单个桶"""
        try:
            # 验证桶名
            is_valid, message = self._validate_bucket_name(bucket_name)
            if not is_valid:
                print(f"❌ 桶名验证失败: {message}")
                return False
            
            s3_client = self._get_client()
            print(f"🏗️  正在创建桶: {bucket_name}")
            
            # 创建桶
            if region and region != 'us-east-1':
                # 非默认区域需要指定 LocationConstraint
                s3_client.create_bucket(
                    Bucket=bucket_name,
                    CreateBucketConfiguration={'LocationConstraint': region}
                )
            else:
                # 默认区域
                s3_client.create_bucket(Bucket=bucket_name)
            
            print(f"✅ 桶创建成功: {bucket_name}")
            print(f"   📅 创建时间: 刚刚")
            print(f"   🌐 区域: {region or 'us-east-1'}")
            print(f"   🔐 默认权限: 私有")
            
            return True
            
        except ClientError as e:
            error_code = e.response['Error']['Code']
            error_msg = e.response['Error']['Message']
            
            if error_code == 'BucketAlreadyOwnedByYou':
                print(f"⚠️  桶已存在: {bucket_name}")
                return True  # 桶已存在不算失败
            elif error_code == 'BucketAlreadyExists':
                print(f"❌ 桶名被占用: {bucket_name}")
                return False
            elif error_code == 'InvalidBucketName':
                print(f"❌ 桶名不合规: {bucket_name} - {error_msg}")
                return False
            else:
                print(f"❌ 创建失败 [{error_code}]: {error_msg}")
                return False
        except NoCredentialsError:
            print("❌ 错误: 未找到 AWS 凭据")
            return False
        except Exception as e:
            print(f"❌ 未知错误: {e}")
            return False
    
    def create_single_bucket_verbose(self, bucket_name, region=None):
        """详细格式创建单个桶"""
        try:
            # 验证桶名
            is_valid, message = self._validate_bucket_name(bucket_name)
            if not is_valid:
                print(f"❌ 桶名验证失败: {message}")
                return False
            
            s3_client = self._get_client()
            print("🏗️  桶创建详细信息:")
            print("=" * 50)
            print(f"   🗂️  桶名称: {bucket_name}")
            print(f"   🌐 目标区域: {region or 'us-east-1'}")
            print(f"   🔗 服务端点: {self.endpoint_url}")
            print(f"   📅 创建时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
            print()
            
            # 创建桶
            if region and region != 'us-east-1':
                # 非默认区域需要指定 LocationConstraint
                s3_client.create_bucket(
                    Bucket=bucket_name,
                    CreateBucketConfiguration={'LocationConstraint': region}
                )
                print(f"   ✅ 桶创建成功 (区域: {region})")
            else:
                # 默认区域
                s3_client.create_bucket(Bucket=bucket_name)
                print(f"   ✅ 桶创建成功 (默认区域)")
            
            # 获取桶信息
            response = s3_client.head_bucket(Bucket=bucket_name)
            print(f"   📅 创建时间: 刚刚")
            print(f"   🌐 区域: {region or 'us-east-1'}")
            print(f"   🔐 默认权限: 私有")
            print(f"   📊 状态: 可用")
            
            return True
            
        except ClientError as e:
            error_code = e.response['Error']['Code']
            error_msg = e.response['Error']['Message']
            
            print(f"   ❌ 创建失败:")
            print(f"      错误代码: {error_code}")
            print(f"      错误信息: {error_msg}")
            
            if error_code == 'BucketAlreadyOwnedByYou':
                print(f"   ⚠️  桶已存在: {bucket_name}")
                return True  # 桶已存在不算失败
            elif error_code == 'BucketAlreadyExists':
                print(f"   ❌ 桶名被占用: {bucket_name}")
                return False
            elif error_code == 'InvalidBucketName':
                print(f"   ❌ 桶名不合规: {bucket_name}")
                return False
            else:
                return False
        except NoCredentialsError:
            print("   ❌ 错误: 未找到 AWS 凭据")
            return False
        except Exception as e:
            print(f"   ❌ 未知错误: {e}")
            return False
    
    def create_single_bucket_json(self, bucket_name, region=None):
        """JSON 格式创建单个桶"""
        try:
            # 验证桶名
            is_valid, message = self._validate_bucket_name(bucket_name)
            if not is_valid:
                result = {
                    "success": False,
                    "bucket_name": bucket_name,
                    "error": "validation_failed",
                    "error_message": message
                }
                print(json.dumps(result, indent=2, ensure_ascii=False))
                return False
            
            s3_client = self._get_client()
            
            # 创建桶
            if region and region != 'us-east-1':
                # 非默认区域需要指定 LocationConstraint
                s3_client.create_bucket(
                    Bucket=bucket_name,
                    CreateBucketConfiguration={'LocationConstraint': region}
                )
            else:
                # 默认区域
                s3_client.create_bucket(Bucket=bucket_name)
            
            # 获取桶信息
            response = s3_client.head_bucket(Bucket=bucket_name)
            result = {
                "success": True,
                "bucket_name": bucket_name,
                "region": region or 'us-east-1',
                "creation_time": datetime.now().isoformat(),
                "status": "available",
                "permissions": "private"
            }
            print(json.dumps(result, indent=2, ensure_ascii=False))
            return True
            
        except ClientError as e:
            error_code = e.response['Error']['Code']
            error_msg = e.response['Error']['Message']
            
            if error_code == 'BucketAlreadyOwnedByYou':
                result = {
                    "success": True,
                    "bucket_name": bucket_name,
                    "status": "already_exists",
                    "message": "桶已存在"
                }
                print(json.dumps(result, indent=2, ensure_ascii=False))
                return True  # 桶已存在不算失败
            else:
                result = {
                    "success": False,
                    "bucket_name": bucket_name,
                    "error": error_code,
                    "error_message": error_msg
                }
                print(json.dumps(result, indent=2, ensure_ascii=False))
                return False
        except NoCredentialsError:
            result = {
                "success": False,
                "error": "NoCredentials",
                "error_message": "未找到 AWS 凭据"
            }
            print(json.dumps(result, indent=2, ensure_ascii=False))
            return False
        except Exception as e:
            result = {
                "success": False,
                "error": "Unknown",
                "error_message": str(e)
            }
            print(json.dumps(result, indent=2, ensure_ascii=False))
            return False


    def create_multiple_buckets(self, name_prefix, count, region=None):
        """简单格式批量创建桶"""
        success_count = 0
        failed_buckets = []
        
        print(f"🏗️  批量创建 {count} 个桶，前缀: {name_prefix}")
        print("-" * 50)
        
        for i in range(1, count + 1):
            bucket_name = f"{name_prefix}{i:03d}"
            if self.create_single_bucket_simple(bucket_name, region):
                success_count += 1
            else:
                failed_buckets.append(bucket_name)
            print()
        
        print("📊 批量创建结果:")
        print(f"   ✅ 成功: {success_count}/{count}")
        print(f"   ❌ 失败: {len(failed_buckets)}/{count}")
        
        if failed_buckets:
            print(f"   失败的桶: {', '.join(failed_buckets)}")
        
        return success_count == count
    
    def create_multiple_buckets_verbose(self, name_prefix, count, region=None):
        """详细格式批量创建桶"""
        success_count = 0
        failed_buckets = []
        
        print("🏗️  批量桶创建详细信息:")
        print("=" * 60)
        print(f"   🏷️  桶名前缀: {name_prefix}")
        print(f"   📊 创建数量: {count}")
        print(f"   🌐 目标区域: {region or 'us-east-1'}")
        print(f"   🔗 服务端点: {self.endpoint_url}")
        print(f"   📅 开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print()
        
        for i in range(1, count + 1):
            bucket_name = f"{name_prefix}{i:03d}"
            print(f"   [{i}/{count}] 创建桶: {bucket_name}")
            
            if self.create_single_bucket_verbose(bucket_name, region):
                success_count += 1
                print(f"   ✅ 成功")
            else:
                failed_buckets.append(bucket_name)
                print(f"   ❌ 失败")
            print()
        
        print("📊 批量创建统计:")
        print(f"   • 总数量: {count}")
        print(f"   • 成功数: {success_count}")
        print(f"   • 失败数: {len(failed_buckets)}")
        print(f"   • 成功率: {(success_count/count)*100:.1f}%")
        
        if failed_buckets:
            print(f"   • 失败桶列表: {', '.join(failed_buckets)}")
        
        return success_count == count
    
    def create_multiple_buckets_json(self, name_prefix, count, region=None):
        """JSON 格式批量创建桶"""
        results = []
        success_count = 0
        
        for i in range(1, count + 1):
            bucket_name = f"{name_prefix}{i:03d}"
            
            # 验证桶名
            is_valid, message = self._validate_bucket_name(bucket_name)
            if not is_valid:
                results.append({
                    "bucket_name": bucket_name,
                    "success": False,
                    "error": "validation_failed",
                    "error_message": message
                })
                continue
            
            try:
                s3_client = self._get_client()
                
                # 创建桶
                if region and region != 'us-east-1':
                    s3_client.create_bucket(
                        Bucket=bucket_name,
                        CreateBucketConfiguration={'LocationConstraint': region}
                    )
                else:
                    s3_client.create_bucket(Bucket=bucket_name)
                
                results.append({
                    "bucket_name": bucket_name,
                    "success": True,
                    "region": region or 'us-east-1',
                    "creation_time": datetime.now().isoformat(),
                    "status": "available"
                })
                success_count += 1
                
            except ClientError as e:
                error_code = e.response['Error']['Code']
                error_msg = e.response['Error']['Message']
                
                if error_code == 'BucketAlreadyOwnedByYou':
                    results.append({
                        "bucket_name": bucket_name,
                        "success": True,
                        "status": "already_exists",
                        "message": "桶已存在"
                    })
                    success_count += 1
                else:
                    results.append({
                        "bucket_name": bucket_name,
                        "success": False,
                        "error": error_code,
                        "error_message": error_msg
                    })
            except Exception as e:
                results.append({
                    "bucket_name": bucket_name,
                    "success": False,
                    "error": "Unknown",
                    "error_message": str(e)
                })
        
        # 输出汇总结果
        summary = {
            "operation": "batch_create_buckets",
            "prefix": name_prefix,
            "total_count": count,
            "success_count": success_count,
            "failed_count": count - success_count,
            "success_rate": f"{(success_count/count)*100:.1f}%",
            "results": results,
            "completion_time": datetime.now().isoformat()
        }
        
        print(json.dumps(summary, indent=2, ensure_ascii=False))
        return success_count == count


    def list_existing_buckets(self, name_filter=None):
        """简单格式列出现有桶"""
        try:
            s3_client = self._get_client()
            response = s3_client.list_buckets()
            buckets = response['Buckets']
            
            if name_filter:
                buckets = [b for b in buckets if name_filter in b['Name']]
            
            if not buckets:
                print("📭 没有找到匹配的桶")
                return True
            
            print(f"📚 现有桶列表 ({len(buckets)} 个):")
            print("-" * 50)
            
            for bucket in sorted(buckets, key=lambda x: x['CreationDate'], reverse=True):
                name = bucket['Name']
                created = bucket['CreationDate'].strftime('%Y-%m-%d %H:%M:%S')
                print(f"🗂️  {name:<30} {created}")
            
            return True
            
        except ClientError as e:
            error_code = e.response['Error']['Code']
            error_msg = e.response['Error']['Message']
            print(f"❌ S3 错误 [{error_code}]: {error_msg}")
            return False
        except NoCredentialsError:
            print("❌ 错误: 未找到 AWS 凭据")
            return False
        except Exception as e:
            print(f"❌ 未知错误: {e}")
            return False
    
    def list_existing_buckets_verbose(self, name_filter=None):
        """详细格式列出现有桶"""
        try:
            s3_client = self._get_client()
            response = s3_client.list_buckets()
            buckets = response['Buckets']
            
            if name_filter:
                buckets = [b for b in buckets if name_filter in b['Name']]
            
            if not buckets:
                print("📭 没有找到匹配的桶")
                return True
            
            print("📚 详细桶信息:")
            print("=" * 70)
            print(f"   🔍 过滤条件: {name_filter or '无'}")
            print(f"   📊 匹配数量: {len(buckets)}")
            print(f"   🔗 服务端点: {self.endpoint_url}")
            print()
            
            for bucket in sorted(buckets, key=lambda x: x['CreationDate'], reverse=True):
                name = bucket['Name']
                created = bucket['CreationDate'].strftime('%Y-%m-%d %H:%M:%S')
                age = self._format_bucket_age(bucket['CreationDate'])
                
                print(f"   🗂️  桶名称: {name}")
                print(f"       📅 创建时间: {created}")
                print(f"       ⏰ 年龄: {age}")
                print(f"       🌐 区域: us-east-1 (默认)")
                print()
            
            return True
            
        except Exception as e:
            print(f"❌ 错误: {e}")
            return False
    
    def list_existing_buckets_json(self, name_filter=None):
        """JSON 格式列出现有桶"""
        try:
            s3_client = self._get_client()
            response = s3_client.list_buckets()
            buckets = response['Buckets']
            
            if name_filter:
                buckets = [b for b in buckets if name_filter in b['Name']]
            
            # 转换为 JSON 友好的格式
            result = {
                "operation": "list_buckets",
                "filter": name_filter,
                "total_count": len(buckets),
                "buckets": [],
                "query_time": datetime.now().isoformat()
            }
            
            for bucket in buckets:
                bucket_info = {
                    "name": bucket['Name'],
                    "creation_date": bucket['CreationDate'].isoformat(),
                    "age_days": (datetime.now(timezone.utc) - bucket['CreationDate']).days
                }
                result["buckets"].append(bucket_info)
            
            print(json.dumps(result, indent=2, ensure_ascii=False))
            return True
            
        except ClientError as e:
            error_code = e.response['Error']['Code']
            error_msg = e.response['Error']['Message']
            error_result = {
                "error": True,
                "error_code": error_code,
                "error_message": error_msg
            }
            print(json.dumps(error_result, indent=2, ensure_ascii=False))
            return False
        except NoCredentialsError:
            error_result = {
                "error": True,
                "error_code": "NoCredentials",
                "error_message": "未找到 AWS 凭据"
            }
            print(json.dumps(error_result, indent=2, ensure_ascii=False))
            return False
        except Exception as e:
            error_result = {
                "error": True,
                "error_code": "Unknown",
                "error_message": str(e)
            }
            print(json.dumps(error_result, indent=2, ensure_ascii=False))
            return False
    
    def _format_bucket_age(self, created_date):
        """计算并格式化桶的年龄"""
        now = datetime.now(timezone.utc)
        age = now - created_date
        
        if age.days == 0:
            return "今天"
        elif age.days == 1:
            return "昨天"
        elif age.days < 7:
            return f"{age.days} 天前"
        elif age.days < 30:
            weeks = age.days // 7
            return f"{weeks} 周前"
        elif age.days < 365:
            months = age.days // 30
            return f"{months} 个月前"
        else:
            years = age.days // 365
            return f"{years} 年前"


def parse_args():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(
        description='S3 CreateBucket API 演示工具',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
示例:
  %(prog)s --name my-new-bucket              # 创建单个桶
  %(prog)s --name my-bucket --region us-west-2  # 指定区域创建
  %(prog)s --name-prefix test --count 5      # 批量创建 5 个桶
  %(prog)s --list                           # 列出现有桶
  %(prog)s --list --filter test             # 列出包含 'test' 的桶
  %(prog)s --format json                    # JSON 格式输出
  %(prog)s --verbose                        # 详细格式输出
  %(prog)s --access-key KEY --secret-key SECRET  # 指定凭据
        """
    )
    
    parser.add_argument(
        '--host',
        default='http://localhost:8000',
        help='S3 服务端点 (默认: http://localhost:8000)'
    )
    
    parser.add_argument(
        '--access-key',
        default='AKIAIOSFODNN7EXAMPLE',
        help='AWS Access Key (默认: 测试密钥)'
    )
    
    parser.add_argument(
        '--secret-key',
        default='wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
        help='AWS Secret Key (默认: 测试密钥)'
    )
    
    parser.add_argument(
        '--region',
        default='us-east-1',
        help='AWS 区域 (默认: us-east-1)'
    )
    
    parser.add_argument(
        '--format',
        choices=['simple', 'verbose', 'json'],
        default='simple',
        help='输出格式 (默认: simple)'
    )
    
    parser.add_argument(
        '--verbose',
        action='store_true',
        help='详细输出模式 (等同于 --format verbose)'
    )
    
    # 创建选项
    create_group = parser.add_mutually_exclusive_group()
    create_group.add_argument(
        '--name',
        help='要创建的桶名称'
    )
    
    create_group.add_argument(
        '--name-prefix',
        help='批量创建时的桶名前缀'
    )
    
    parser.add_argument(
        '--count',
        type=int,
        default=1,
        help='批量创建的桶数量 (默认: 1)'
    )
    
    # 列表选项
    parser.add_argument(
        '--list',
        action='store_true',
        help='列出现有桶'
    )
    
    parser.add_argument(
        '--filter',
        help='过滤桶名（用于 --list）'
    )
    
    parser.add_argument(
        '--dry-run',
        action='store_true',
        help='模拟运行，不实际创建桶'
    )
    
    return parser.parse_args()


def main():
    """主函数"""
    args = parse_args()
    
    # 如果指定了 --verbose，覆盖 format 设置
    if args.verbose:
        args.format = 'verbose'
    
    # 参数验证
    if not args.list and not args.name and not args.name_prefix:
        print("❌ 错误: 必须指定 --name、--name-prefix 或 --list 之一")
        sys.exit(1)
    
    if args.name_prefix and args.count < 1:
        print("❌ 错误: --count 必须大于 0")
        sys.exit(1)
    
    # 创建客户端
    client = BucketCreateClient(
        endpoint_url=args.host,
        access_key=args.access_key,
        secret_key=args.secret_key,
        region=args.region
    )
    
    # 根据格式执行相应操作
    success = False
    
    if args.list:
        if args.format == 'simple':
            success = client.list_existing_buckets_simple(args.filter)
        elif args.format == 'verbose':
            success = client.list_existing_buckets_verbose(args.filter)
        elif args.format == 'json':
            success = client.list_existing_buckets_json(args.filter)
    elif args.dry_run:
        if args.name:
            is_valid, message = client._validate_bucket_name(args.name)
            print(f"🔍 桶名验证: {args.name}")
            print(f"   结果: {'✅' if is_valid else '❌'} {message}")
            success = True
        elif args.name_prefix:
            print(f"🔍 模拟批量创建:")
            for i in range(1, args.count + 1):
                bucket_name = f"{args.name_prefix}{i:03d}"
                is_valid, message = client._validate_bucket_name(bucket_name)
                status = '✅' if is_valid else '❌'
                print(f"   {status} {bucket_name}: {message}")
            success = True
    else:
        if args.name:
            if args.format == 'simple':
                success = client.create_single_bucket_simple(args.name, args.region)
            elif args.format == 'verbose':
                success = client.create_single_bucket_verbose(args.name, args.region)
            elif args.format == 'json':
                success = client.create_single_bucket_json(args.name, args.region)
        elif args.name_prefix:
            if args.format == 'simple':
                success = client.create_multiple_buckets_simple(args.name_prefix, args.count, args.region)
            elif args.format == 'verbose':
                success = client.create_multiple_buckets_verbose(args.name_prefix, args.count, args.region)
            elif args.format == 'json':
                success = client.create_multiple_buckets_json(args.name_prefix, args.count, args.region)
    
    # 设置退出码
    sys.exit(0 if success else 1)


if __name__ == '__main__':
    main()
